/* $Id: Show.java,v 1.38 2007/10/29 14:18:35 gigabass Exp $
 *
 * Copyright (c) Guido Ludwig. All rights reserved.
 * Use is subject to license terms.
 */

package de.guidoludwig.jtm.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.Columns;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Type;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;

/**
 * Domain Object for a Show
 * 
 * @author <a href="mailto:jtrade@gigabss.de">Guido Ludwig</a>
 * @version $Revision: 1.38 $
 */

@Entity
@Indexed
public class Show extends NamedPersistentObject {

	public static final String PROPERTY_ARTIST = "artist"; //$NON-NLS-1$
	public static final String PROPERTY_LOCATION = "location"; //$NON-NLS-1$
	public static final String PROPERTY_MEDIA = "media"; //$NON-NLS-1$
	public static final String PROPERTY_RECORDING_GRADE = "recordingGrade"; //$NON-NLS-1$
	public static final String PROPERTY_LENGTH = "length"; //$NON-NLS-1$
	public static final String PROPERTY_SHOW_REMARKS = "showRemarks"; //$NON-NLS-1$
	public static final String PROPERTY_RECORDING_REMARKS = "recordingRemarks"; //$NON-NLS-1$
	public static final String PROPERTY_SOURCE = "source"; //$NON-NLS-1$
	public static final String PROPERTY_STATUS = "status"; //$NON-NLS-1$
	public static final String PROPERTY_RECEIVED_DATE = "receivedDate"; //$NON-NLS-1$
	public static final String PROPERTY_SHOW_DATE = "showDate"; //$NON-NLS-1$
	public static final String PROPERTY_MASTER = "master"; //$NON-NLS-1$
	public static final String PROPERTY_TRADER = "trader"; //$NON-NLS-1$
	public static final String PROPERTY_ARCHIVE = "archive"; //$NON-NLS-1$
	public static final String PROPERTY_PRIVATE = "private"; //$NON-NLS-1$
	public static final String PROPERTY_LINEAGE = "lineage"; //$NON-NLS-1$
	public static final String PROPERTY_SETLIST = "setlist"; //$NON-NLS-1$
	public static final String PROPERTY_MUSICIANS = "musicians"; //$NON-NLS-1$

	public static final String SEARCHFIELD_NAME = "name"; //$NON-NLS-1$
	public static final String SEARCHFIELD_ARTIST_NAME = "artist.name"; //$NON-NLS-1$
	public static final String SEARCHFIELD_LOCATION_VENUE = "location.venue"; //$NON-NLS-1$
	public static final String SEARCHFIELD_LOCATION_CITY = "location.city"; //$NON-NLS-1$
	public static final String SEARCHFIELD_LOCATION_COUNTRY_CODE = "location.country.code"; //$NON-NLS-1$
	public static final String SEARCHFIELD_LOCATION_COUNTRY_NAME = "location.country.name"; //$NON-NLS-1$
	public static final String SEARCHFIELD_SHOW_DATE = "showDate"; //$NON-NLS-1$

	@ManyToOne(fetch = FetchType.EAGER)
	@ForeignKey(name = "FK_SHOW_ARTIST")
	@IndexedEmbedded(depth = 1)
	private Artist artist;

	@IndexedEmbedded(depth = 1)
	private Location location;

	@Type(type = "de.guidoludwig.jtm.hibernate.EnumUserType", parameters = @org.hibernate.annotations.Parameter(name = "type", value = "de.guidoludwig.jtm.domain.Grade"))
	private Grade recordingGrade;

	private int length; // length in seconds

	@ElementCollection(targetClass = Musician.class)
	@JoinTable(name = "SHOW_MUSICIANS")
	@JoinColumn(name = "show_OID")
	@ForeignKey(name = "FK_SHOW_MUSICIANS")
	private final List<Musician> musicians;

	@ElementCollection(targetClass = Song.class)
	@JoinTable(name = "SHOW_SONGS")
	@JoinColumn(name = "show_OID")
	@ForeignKey(name = "FK_SHOW_SONGS")
	private final List<Song> setlist;

	private String showRemarks;

	private String recordingRemarks;

	@Type(type = "de.guidoludwig.jtm.hibernate.EnumUserType", parameters = @org.hibernate.annotations.Parameter(name = "type", value = "de.guidoludwig.jtm.domain.Source"))
	private Source source;

	@Type(type = "de.guidoludwig.jtm.hibernate.EnumUserType", parameters = @org.hibernate.annotations.Parameter(name = "type", value = "de.guidoludwig.jtm.domain.TradeStatus"))
	private TradeStatus status;

	@Temporal(TemporalType.TIMESTAMP)
	private Date receivedDate;

	@org.hibernate.annotations.Type(type = "de.guidoludwig.jtm.hibernate.FuzzyDateUserType")
	@Columns(columns = { @Column(name = "showYear"),
			@Column(name = "showMonth"), @Column(name = "showDay") })
	private FuzzyDate showDate;

	private boolean master;
	private String trader;

	@ManyToOne(fetch = FetchType.EAGER)
	@ForeignKey(name = "FK_SHOW_ARCHIVE")
	private Archive archive;
	private boolean isPrivate;
	private String lineage;

	@ElementCollection(targetClass = Media.class, fetch=FetchType.EAGER)
	@JoinTable(name = "SHOW_MEDIA")
	@JoinColumn(name = "show_OID")
	@ForeignKey(name = "FK_SHOW_MEDIA")
	private final List<Media> media;

	public Show() {
		super();
		location = new Location();
		media = new ArrayList<Media>();
		recordingGrade = Grade.UNGRADED;
		source = Source.UNKNOWN;
		musicians = new ArrayList<Musician>();
		setlist = new ArrayList<Song>();
		status = TradeStatus.CONFIRMED;
	}

	// --------------------------------------------------------------------
	// getter methods
	// --------------------------------------------------------------------
	public String getLineage() {
		return lineage;
	}

	public Artist getArtist() {
		return artist;
	}

	public Location getLocation() {
		return location;
	}

	public List<Media> getMedia() {
		return media;
	}

	public boolean isPrivate() {
		return isPrivate;
	}

	public Grade getRecordingGrade() {
		return recordingGrade;
	}

	public List<Musician> getMusicians() {
		return musicians;
	}

	public List<Song> getSetlist() {
		return setlist;
	}

	public String getShowRemarks() {
		return showRemarks;
	}

	public String getRecordingRemarks() {
		return recordingRemarks;
	}

	public TradeStatus getStatus() {
		return status;
	}

	public FuzzyDate getShowDate() {
		return showDate;
	}

	public boolean isMaster() {
		return master;
	}

	public String getTrader() {
		return trader;
	}

	public Source getSource() {
		return source;
	}

	// --------------------------------------------------------------------
	// setter methods
	// --------------------------------------------------------------------

	public void setPrivate(boolean newValue) {
		boolean oldValue = isPrivate;
		isPrivate = newValue;
		firePropertyChange(PROPERTY_PRIVATE, oldValue, isPrivate);
	}

	public void setLineage(String newValue) {
		String oldlineage = lineage;
		lineage = newValue == null ? null : newValue.trim();
		firePropertyChange(PROPERTY_LINEAGE, oldlineage, lineage);
	}

	public void setArtist(Artist newValue) {
		Artist oldArtist = artist;
		artist = newValue;
		firePropertyChange(PROPERTY_ARTIST, oldArtist, artist);
	}

	public void setLocation(Location newValue) {
		Location oldLocation = location;
		location = newValue;
		firePropertyChange(PROPERTY_LOCATION, oldLocation, location);
	}

	public void setRecordingGrade(Grade newValue) {
		Object oldGrade = recordingGrade;
		if (newValue == null) {
			recordingGrade = Grade.UNGRADED;
		} else {
			recordingGrade = newValue;
		}
		firePropertyChange(PROPERTY_RECORDING_GRADE, oldGrade, recordingGrade);
	}

	public void setShowRemarks(String newValue) {
		String old = showRemarks;
		showRemarks = (newValue == null ? null : newValue.trim());
		firePropertyChange(PROPERTY_SHOW_REMARKS, old, showRemarks);
	}

	public void setRecordingRemarks(String newValue) {
		String old = recordingRemarks;
		recordingRemarks = (newValue == null ? null : newValue.trim());
		firePropertyChange(PROPERTY_RECORDING_REMARKS, old, recordingRemarks);
	}

	public void setStatus(TradeStatus newValue) {
		TradeStatus old = status;
		this.status = newValue;
		firePropertyChange(PROPERTY_STATUS, old, status);
	}

	public void setShowDate(FuzzyDate newValue) {
		FuzzyDate old = getShowDate();
		showDate = newValue;
		firePropertyChange(PROPERTY_SHOW_DATE, old, showDate);
	}

	public void setMaster(boolean newValue) {
		boolean old = master;
		master = newValue;
		firePropertyChange(PROPERTY_MASTER, old, master);
	}

	public void setTrader(String newValue) {
		String old = trader;
		trader = newValue == null ? null : newValue.trim();
		firePropertyChange(PROPERTY_TRADER, old, trader);
	}

	// -------------------------------------------------------
	// convenience methods

	public boolean isTradeable() {
		return (status.equals(TradeStatus.TRADEABLE));
	}

	public boolean isConfirmed() {
		return (status.equals(TradeStatus.CONFIRMED) || status
				.equals(TradeStatus.ANNOUNCED));
	}

	public boolean setlistAvailable() {
		if (setlist == null || setlist.size() == 0) {
			return (false);
		}
		return (true);
	}

	// -------------------------------------------------------
	// List management

	public void addSong(Song s) {
		if (setlist.add(s)) {
			firePropertyChange(PROPERTY_SETLIST, null, getSetlist());
		}
	}

	public void addMusician(Musician m) {
		if (musicians.add(m)) {
			firePropertyChange(PROPERTY_MUSICIANS, null, getMusicians());
		}
	}

	public void addMedia(Media m) {
		if (media.add(m)) {
			firePropertyChange(PROPERTY_MEDIA, null, getMedia());
		}
	}

	public void setSource(Source s) {
		Object oldSource = source;
		source = (s == null ? Source.UNKNOWN : s);
		firePropertyChange(PROPERTY_SOURCE, oldSource, source);
	}

	/**
	 * @return Returns the receivedDate.
	 */
	public Date getReceivedDate() {
		return receivedDate;
	}

	/**
	 * @param receivedDate
	 *            The receivedDate to set.
	 */
	public void setReceivedDate(Date receivedDate) {
		Object old = this.receivedDate;
		this.receivedDate = receivedDate;
		firePropertyChange(PROPERTY_RECEIVED_DATE, old, this.receivedDate);
	}

	public String getNumberedSetlist() {
		StringBuffer sb = new StringBuffer();
		if (setlist != null) {
			for (int i = 0; i < setlist.size(); i++) {
				sb.append((i + 1) + " " + setlist.get(i) + "  ");
			}
		}
		return (sb.toString());
	}

	/**
	 * @return Returns the length.
	 */
	public int getLength() {
		return length;
	}

	/**
	 * @param length
	 *            The length to set.
	 */
	public void setLength(int length) {
		Object old = this.length;
		this.length = length;
		firePropertyChange(PROPERTY_LENGTH, old, this.length);
	}

	public Archive getArchive() {
		return archive;
	}

	public void setArchive(Archive archive) {
		Object old = this.archive;
		this.archive = archive;
		firePropertyChange(PROPERTY_ARCHIVE, old, this.archive);
	}

	@SuppressWarnings("unused")
	@Field(name = SEARCHFIELD_SHOW_DATE)
	private String getLuceneShowDate() {
		return showDate == null ? null : showDate.getYear() + "-" 
				+ showDate.getMonth() + "-"  + showDate.getDay();
	}

	@SuppressWarnings("unused")
	@Field(name = SEARCHFIELD_LOCATION_COUNTRY_CODE)
	private String getLuceneCountryCode() {
		return location == null ? null : location.getCountry() == null ? null
				: location.getCountry().name();
	}
	@SuppressWarnings("unused")
	@Field(name = SEARCHFIELD_LOCATION_COUNTRY_NAME)
	private String getLuceneCountryName() {
		return location == null ? null : location.getCountry() == null ? null
				: location.getCountry().getCountryName();
	}
}